package com.macro.mall.util;


import org.apache.commons.lang.StringUtils;

import javax.validation.constraints.NotBlank;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;

/**
 * @author wanglei
 * @since 05.17.2017
 */
public final class StringUtil {

    /**
     * 手机号正则表达式
     */
    private static final Pattern MOBILE_PATTERN = Pattern.compile("^1[3-9][0-9]{9}$");

    private static final Pattern NAME_PATTERN = Pattern.compile("[\\u4E00-\\u9FA5|·]{2,15}");

    private static final Pattern CHINESE_ID = Pattern.compile("^\\d{17}[\\d|X|x]$");

    /**
     * 年龄1-999的正则表达式
     */
    private static final Pattern AGE_PATTERN = Pattern.compile("^[1-9][0-9]{0,2}$");

    private StringUtil() {

    }

    public static boolean isNotMobile(String mobile) {
        return !StringUtil.isNotEmpty(mobile) || !MOBILE_PATTERN.matcher(mobile).matches();
    }

    /**
     * 判断是否为空
     *
     * @param str 字符串
     * @return true表示为空，false表示不为空
     */
    public static boolean isEmpty(String str) {
        return null == str || "".equals(str) || "".equals(str.trim());
    }

    /**
     * 判断是否不为空值
     *
     * @param str 字符串
     * @return true表示不为空值，false表示为空值
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    public static boolean isNullOrEmpty(Object obj) {
        if (obj == null) {
            return true;
        }

        if (obj instanceof CharSequence) {
            return ((CharSequence) obj).toString().trim().length() == 0;
        }

        if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        }

        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }

        if (obj instanceof Number) {
            return "0".equals( obj.toString());
        }

        if (obj instanceof Object[]) {
            Object[] object = (Object[]) obj;
            if (object.length == 0) {
                return true;
            }
            boolean empty = true;
            for (Object anObject : object) {
                if (!isNullOrEmpty(anObject)) {
                    empty = false;
                    break;
                }
            }
            return empty;
        }
        return false;
    }

    /**
     * 判断对象属性是否全部为空，是返回true
     * @param object
     * @return
     */
    public static boolean checkObjAllFieldsIsNull(Object object) {
        if (null == object) {
            return true;
        }
        try {
            for (Field f : object.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                boolean nullOrEmpty = isNullOrEmpty(f.get(object));
                if (!nullOrEmpty) {
                    return false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 根据类上的注解判断必填项是否为空
     *
     * @return ture为校验通过，false为必填项有空值
     */
    public static <T> Boolean checkDataNotBlank(T data) {
        if (data == null) {
            return false;
        }
        Field[] entryFields = data.getClass().getDeclaredFields();
        for (Field field : entryFields) {
            NotBlank notBlank = field.getAnnotation(NotBlank.class);
            if (notBlank == null) {
                continue;
            }
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(data);
                if (StringUtil.isNullOrEmpty(fieldValue)) {
                    return false;
                }
            } catch (IllegalAccessException e) {
                throw new ApiException("1210101");
            }
        }
        return true;
    }

    /**
     * 姓名格式校验
     *
     * @param name 姓名
     * @return true表示格式校验通过，false表示不通过
     */
    public static boolean isCheckName(String name) {
        return isNotEmpty(name) && name.length() >= 2 && name.length() <= 15 && NAME_PATTERN.matcher(name).matches();

    }


    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    public static String phoneAddMark(String phone) {
        if (isNotEmpty(phone)) {
            return phone.substring(0, 3) + "****" + phone.substring(7);
        }
        return phone;
    }

    public static boolean isName(String name) {
        return isNotEmpty(name) && NAME_PATTERN.matcher(name).matches();
    }

    public static boolean isAge(String age) {
        return StringUtil.isNotEmpty(age) && AGE_PATTERN.matcher(age).matches();
    }

    /**
     * 脱敏身份证号
     * @param idCard 身份证号
     */
    public static String idCardHidden(String idCard) {
        if (idCard != null && idCard.length() == 18) {
            return idCard.substring(0, 12) + "******";
        }
        return idCard;
    }

    /**
     * 身份证验证
     *
     * @param certNo 号码内容
     * @return 是否有效 null和"" 都是false
     */
    public static boolean isIDCard(String certNo) {
        if (certNo == null || certNo.length() != 18 || !CHINESE_ID.matcher(certNo).matches()){
            return false;
        }

        final int birthDay = Integer.parseInt(certNo.substring(6, 14));

        //校验年份
        final int iyear = birthDay / 10000;
        if (iyear <= 1900 || iyear >= LocalDate.now().getYear()){
            return false;
        }

        //校验天数
        final int iday = birthDay % 100;
        if (iday <= 0 || iday >= 32){
            return false;
        }

        //校验月份
        final int imonth = birthDay % 10000 / 100;
        if (imonth <= 0 || imonth >= 13) {
            return false;
        }

        //校验位数
        int power = 0;
        final char[] cs = certNo.toUpperCase().toCharArray();
        int[] powerArray = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        int[] parityBit = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
        int indexRemark = cs.length -1;
        for (int i = 0; i < indexRemark; i++) {
            power += (cs[i] - '0') * powerArray[i];
        }

        return cs[indexRemark] == parityBit[power % 11];
    }

    /**
     * 根据身份证号码计算年龄
     *
     * @param idCard 考虑到了15位身份证，但不一定存在
     */
    public static String getBirthdayByIdCard(String idCard) {
        if (idCard.length() == 15) {
            return "19" + idCard.substring(6, 12);
        } else if (idCard.length() == 18) {
            return idCard.substring(6, 14);
        }
        return "";
    }

    /**
     * 获取身份证中性别标识位的值
     * @param idCard 身份证
     * @return 返回值
     */
    public static Integer getSexIntegerFromIdCard(String idCard) {
        try {
            return Integer.parseInt(idCard.substring(idCard.length() - 2, idCard.length() - 1));
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 将字符串开始位置到结束位置之间的字符用指定字符替换
     * @param sourceStr 待处理字符串
     * @param begin	开始位置 包含
     * @param end	结束位置 不包含
     * @param replacement 替换字符
     * @return String
     */
    public static String replaceBetween(String sourceStr, int begin, int end, String replacement) {
        if (sourceStr == null) {
            return "";
        }
        if (replacement == null) {
            replacement = "*";
        }
        int replaceLength = end - begin;
        if (StringUtils.isNotBlank(sourceStr) && replaceLength > 0) {
            StringBuilder sb = new StringBuilder(sourceStr);
            sb.replace(begin, end, StringUtils.repeat(replacement, replaceLength));
            return sb.toString();
        } else {
            return sourceStr;
        }
    }

    /**
     * 姓名脱敏
     * @param name 姓名
     * @return String
     */
    public static String replaceName(String name) {
        if (StringUtils.isBlank(name)) {
            return "";
        }
        // 姓名为两个字的
        if (name.length() == 2) {
            name = name.replaceFirst(name.substring(0,1), "*");
        }
        // 姓名为三个字的
        if (name.length() > 2) {
            // 姓氏
            StringBuilder familyName = new StringBuilder(name.substring(0, 1));
            // 名字的最后一个字
            String givenName = name.substring(name.length() - 1, name.length());
            for (int i = name.length() - 2; i > 0; i --) {
                familyName.append("*");
            }
            name = familyName + givenName;
        }
        return name;
    }

    /**
     * 判断字符串中含有某个字符的次数
     * @author zengcy
     * @date 2021/11/24
     */
    public static int contains(String str, String character) {
        int count=0;
        while (str.contains(character)) {
            str = str.substring(str.indexOf(character)+1);
            ++count;
        }
        return count;
    }


    /**
     * sql关键词校验
     * @param sql sql
     * @author chang
     * @return 若包含非法字符返回ture，否则返回false
     */
    public static boolean sqlValidate(String sql) {
        if (isEmpty(sql)) {
            return false;
        }
        // 过滤掉的sql关键字，可以手动添加
        String badStr = "insert|select|delete|update|insert|count|drop|like|create|table|where|order|from|column_name|group|*|%|;|-|+|,|'|/|#|" +
                "information_schema.columns|table_schema|union";
        String[] badStrArr = badStr.split("\\|");
        for (String s : badStrArr) {
            // 统一转为小写
            if (sql.toLowerCase().contains(s)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 校验银行卡卡号(比较算出的校验位和卡号里的校验位)
     * @param cardId
     * @return
     */
    public static boolean isBankCard(String cardId) {
        return cardId != null && cardId.trim().length() > 0
                && cardId.matches("\\d+");
//        char bit = getBankCardCheckCode(cardId.substring(0, cardId.length() - 1));
//        return cardId.charAt(cardId.length() - 1) == bit;
    }

    /**
     * 用不含校验位的银行卡卡号，采用 Luhm 校验算法获得校验位(卡号最后一位为校验位)
     * @param nonCheckCodeCardId
     * @return
     */
    private static char getBankCardCheckCode(String nonCheckCodeCardId) {
        char[] chs = nonCheckCodeCardId.trim().toCharArray();
        int luhmSum = 0;
        for(int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
            int k = chs[i] - '0';
            if(j % 2 == 0) {
                k *= 2;
                k = k / 10 + k % 10;
            }
            luhmSum += k;
        }
        return (luhmSum % 10 == 0) ? '0' : (char)((10 - luhmSum % 10) + '0');
    }

    /**
     * 任务编辑日志备注字符串拼接
     * @author zengcy
     * @date 2022/5/18
     * @param remark 备注
     * @param type 修改类型
     * @param oldName 修改前名称
     * @param newName 修改后名称
     * @return java.lang.StringBuilder
     **/
    public static StringBuilder taskEditLog(StringBuilder remark, String type, String oldName, String newName) {
        if(StringUtil.isEmpty(oldName)){
            oldName = "";
        }
        if(StringUtil.isEmpty(newName)) {
            newName = "";
        }
        return remark.append(type).append("由\"").append(oldName).append("\"改为\"").append(newName)
                .append("\"");
    }

    /**
     * 对集合进行分类并按照数量排序
     * @author zengcy
     * @date 2022/6/8
     * @param list 数据列表
     * @return java.util.List<java.util.Map.Entry<java.lang.String,java.lang.Integer>>
     **/
    public static List<Entry<String,Integer>> countRate(List<String> list) {
        Map<String, Integer> map = new HashMap<>(list.size() * 2);

        for (String e: list) {
            if(map.containsKey(e)){
                Integer i = map.get(e);
                map.put(e, i + 1);
            }else {
                map.put(e, 1);
            }
        }
        List<Entry<String,Integer>> resultList = new ArrayList(map.entrySet());
        resultList.sort((o1, o2) -> (o2.getValue() - o1.getValue()));
        return resultList;
    }
}